LeetCode-40-组合总和 II
in LeetCode with 0 comment

LeetCode-40-组合总和 II

in LeetCode with 0 comment

原题地址:组合总和 II

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

说明:

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

示例 2:

输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
  [1,2,2],
  [5]
]

回溯算法

组合总数 相比,这一题中的数字不是可能重复任意次数,它的重复次数将是该数字在candidates中本身出现的次数。其它过程与上一题是一样的:

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
const combinationSum1 = function(candidates, target) {
    candidates.sort((a, b) => a - b);

    /**
     * 求解从某一个位置开始,后面部分得到的和为sum的组合
     * @param index 开始位置
     * @param sum 要求的和
     * @returns {[]|Array} 得到的结果集
     */
    const combine = (index, sum) => {
        // 数组已处理完,不会有新的结果出现,返回空数组
        if (index === candidates.length) {
            return [];
        }
        // 因为已经排过序,如果要处理的第一个数就比要得到的sum大,显然求和后是要大于sum的
        if (candidates[index] > sum) {
            return [];
        }
        let result = [];
        // 求解当前数字的重复次数
        let count = 1;
        for (let i = index + 1; i < candidates.length; i ++) {
            if (candidates[i] !== candidates[index]) {
                break;
            }
            count ++;
        }
        // 当前数字最多只能重复count次
        for (let i = 0; i <= count; i ++) {
            // 得到了结果,将结果保存到result中
            if (sum === i * candidates[index]) {
                result.push(new Array(i).fill(candidates[index]));
            } else {
                // 将sum减去i次第一个数,然后递归求解后面的部分
                // 注意这里是直接跳到后面第一个不重复的位置,因为重复的我们已经通过循环处理过了
                let array = combine(index + count, sum - i * candidates[index]);
                // 如果后面部分有解,就进行合并
                if (array.length > 0) {
                    for (let j = 0; j < array.length; j ++) {
                        result.push(new Array(i).fill(candidates[index]).concat(array[j]));
                    }
                }
            }
        }
        return result;
    };
    // 从0开始求解
    return combine(0, target);
};

测试:

let start = new Date();
const test = combinationSum1;
console.log(test([10,1,2,7,6,1,5], 8)); // [ [ 2, 6 ], [ 1, 7 ], [ 1, 2, 5 ], [ 1, 1, 6 ] ]
console.log(test([2,5,2,1,2], 5)); // [ [ 5 ], [ 1, 2, 2 ] ]
console.log(new Date().getTime() - start.getTime()); // 8